#pragma once

#include <windows.h>
#include <tchar.h>
#include <gdiplus.h>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <set>
#include <fstream>
#include <iostream>
#include <algorithm>

using	namespace	std;
using	namespace	Gdiplus;

class CImageEx
{
	public:
		CImageEx(void);
		~CImageEx(void);
		
		static	int		Initialize();
		static	void	Release();
		static	int		GetEncoderClsid(const WCHAR* format, CLSID* pClsid);

		static	EncoderParameters	m_EncoderParameters;
		static	ULONG_PTR			m_GdiplusToken;
		static	CLSID				m_jpegClsid, m_bmpClsid, m_gifClsid, m_pngClsid, m_tiffClsid;
		
	public:	
		Bitmap		*m_pBitmap;
		BitmapData	m_bitmapData;
		RGBQUAD		*m_pBits;

	public:	
		int			Load(LPCWSTR filename);
		int			Load(LPCSTR filename);
		int			Load(PBYTE pImageData, int size);
		int			Save(LPCWSTR filename);
		int			Save(LPCSTR filename);
		CImageEx*	Duplicate();

		void		Unload();
		int			Draw(HWND hWnd, const RECT& srcRect, const RECT& destRect);
		int			Draw(HDC hDc, const RECT& srcRect, const RECT& destRect);
		
		//width, height
		int			GetWidth()	{ if(m_pBitmap) return m_pBitmap->GetWidth(); return 0; };
		int			GetHeight()	{ if(m_pBitmap) return m_pBitmap->GetHeight(); return 0; };

		int			Resize(IN const int Width,IN const int Height);
		
		int			Height(void)	{ return GetHeight(); };
		int			Width(void)		{ return GetWidth(); };
		bool		IsValid()		{ return ( NULL != m_pBitmap);	};
		bool		LoadPicture(IN const char *szPicName, int iScaleNum=1, int iScaleDenom=1) 
					{ return ( ERROR_SUCCESS == Load((LPCSTR)szPicName) ); };
		unsigned char*	GetPixel(IN const int x,IN const int y);


		//bytes of one line
		int			GetStride() { if(m_pBitmap) return m_bitmapData.Stride; };

		PBYTE		GetBits(RECT* pRect = NULL, int format = 32);
		int			FreeBits();
		
		float		EvalColorful();
		float		EvalContrast();
		double		EvalSize(void);

	public:
		int		RgbToGray(BYTE red, BYTE green, BYTE blue);
		int		RGBQuad2YUV(RGBQUAD *pRGBImage,BYTE *pYImage,BYTE *pUImage,BYTE *pVImage,int iWidth,int iHeight,int iStride );

		// Operations
		int		ConvertToARGB32Bits();
		int		ConvertToRGB24Bits();		//Add by YuanHao Chen; Convert 8Bits/16Bits to 24Bits
		int		ConvertToThumbnail();
		void	GrayScale();
		void	Negative();
		void	HistogramEqualize();
};

inline wstring UTF82WChar(const BYTE * pszSrc, int nLen)
{
	int nSize = MultiByteToWideChar(CP_UTF8,
		0, 
		(LPCSTR)pszSrc,
		nLen,
		0,
		0);
	if (nSize <= 0) 
	{
		return NULL;
	}
	WCHAR * pwszDst	= new WCHAR[nSize + 1];
	if (NULL == pwszDst) 
	{
		return NULL;
	}
	MultiByteToWideChar(CP_UTF8,
		0,
		(LPCSTR) pszSrc,
		nLen,
		pwszDst,
		nSize);
	pwszDst[nSize] = L'\0';
	// skip 0xfeff
	if (pwszDst[0] == 0xFEFF)			//skip UTF8 head if needed
	{
		for (int i = 0; i < nSize; i++)
		{
			pwszDst[i] = pwszDst[i + 1];
		}
	}

	wstring wstrTemp = pwszDst;
	delete[] pwszDst;

	return wstrTemp;
}


inline wstring UTF82WChar(const string strSrc)
{
	return UTF82WChar((const BYTE *)strSrc.c_str(),(int)strSrc.length());
}

